package com.ruoyi.web.service.impl;

import com.aliyun.oss.*;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.PutObjectRequest;
import com.ruoyi.web.core.config.OSSConfig;
import com.ruoyi.web.service.FileService;
import com.ruoyi.web.service.StsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.Map;

/**
 * 文件上传业务类
 *
 * @author zr 2024/2/29
 */
@Service
@Slf4j
public class FileServiceImpl implements FileService {
    @Autowired
    private OSSConfig ossConfig;
    @Autowired
    private StsService stsService;

    /**
     * 上传文件
     *
     * @param file
     * @param objectName
     * @return
     * @throws com.aliyuncs.exceptions.ClientException
     */
    public String upload(MultipartFile file, String objectName) throws com.aliyuncs.exceptions.ClientException {
        // 格式：src/avatar/user.jpg

        // 以华东1（杭州）的外网Endpoint为例，其它Region请按实际情况填写。
        String endpoint = ossConfig.getOosEndPoint();
        // 从环境变量中获取访问凭证。运行本代码示例之前，请确保已通过环境变量设置临时访问密钥（OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET）以及安全令牌（OSS_SESSION_TOKEN）。
//        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        Map<String, String> tokenMap = stsService.getStsToken();
        String assessKeyId = tokenMap.get("Access Key Id");
        String securityAssessKey = tokenMap.get("Access Key Secret");
        String securityToken = tokenMap.get("Security Token");
        // 填写Bucket名称，例如examplebucket。
        String bucketName = ossConfig.getBucketName();
        // 填写Object完整路径，例如example.txt。Object完整路径中不能包含Bucket名称。
//        String objectName = "example.txt";
        // 填写本地文件完整路径。
//        String pathName = "D:\\examplefile.txt";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, assessKeyId, securityAssessKey, securityToken);

        try {
            // 填写本地文件的完整路径。如果未指定本地路径，则默认从示例程序所属项目对应本地路径中上传文件。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, file.getInputStream());
            ossClient.putObject(putObjectRequest);
            return "上传成功";
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return "上传失败";
    }

    /**
     * 删除文件
     *
     * @param objectName
     * @return
     * @throws Exception
     */
    public String del(String objectName) {
        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = ossConfig.getOosEndPoint();
        // 从环境变量中获取访问凭证。运行本代码示例之前，请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
//        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        Map<String, String> tokenMap = stsService.getStsToken();
        String assessKeyId = tokenMap.get("Access Key Id");
        String securityAssessKey = tokenMap.get("Access Key Secret");
        String securityToken = tokenMap.get("Security Token");
        // 填写Bucket名称，例如examplebucket。
        String bucketName = ossConfig.getBucketName();
        // 填写文件完整路径。文件完整路径中不能包含Bucket名称。
//        String objectName = "exampleobject.txt";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, assessKeyId, securityAssessKey, securityToken);

        try {
            // 删除文件或目录。如果要删除目录，目录必须为空。
            ossClient.deleteObject(bucketName, objectName);
            return "删除成功";
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return "删除失败";
    }

    /**
     * 获取文件url
     *
     * @param objectName
     * @return
     * @throws Exception
     */
    public URL getUrl(String objectName) {
        // objectName格式为： src/post/1234.jpg

        // 以华东1（杭州）的外网Endpoint为例，其它Region请按实际情况填写。
        String endpoint = ossConfig.getOosEndPoint();
        // 从环境变量中获取访问凭证。运行本代码示例之前，请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
//        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        Map<String, String> tokenMap = stsService.getStsToken();
        String assessKeyId = tokenMap.get("Access Key Id");
        String securityAssessKey = tokenMap.get("Access Key Secret");
        String securityToken = tokenMap.get("Security Token");
        // 填写Bucket名称，例如examplebucket。
        String bucketName = ossConfig.getBucketName();
        // 填写Object完整路径，例如exampleobject.txt。Object完整路径中不能包含Bucket名称。

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, assessKeyId, securityAssessKey, securityToken);

        URL signedUrl = null;
        try {
            // 指定生成的签名URL过期时间，单位为毫秒。本示例以设置过期时间为1小时为例。
            Date expiration = new Date(new Date().getTime() + 3600 * 1000L);

            // 生成签名URL。
            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);
            // 设置过期时间。
            request.setExpiration(expiration);

            // 通过HTTP GET请求生成签名URL。
            signedUrl = ossClient.generatePresignedUrl(request);
            // 打印签名URL。
            System.out.println("signed url for getObject: " + signedUrl);
            return signedUrl;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
            return null;
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
            return null;
        }
    }


}
